home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************\
- ** TIMING CODE MODULE (80x86 specific code!) **
- **=========================================================================**
- ** Written by Ethan Rohrer, (c) Nuthing Software, December 4, 1994 **
- ** **
- ** Revision History **
- ** ---------------- **
- ** Date Description **
- ** --------- --------------------------------------------------------- **
- ** 13 May 94 Initial Release **
- ** 04 Dec 94 Updated code to conform to current coding standards/style **
- ** Allowed appl. to specify # of timers as param. to TM_Init **
- ** Standardized error handling with function _TM_Error **
- **=========================================================================**
- ** This file contains code which makes use of system timer 0. This timer **
- ** normally operates at a frequency of 1.1932MHz, regardless of the speed **
- ** of the CPU. Normally, this timer is operating in mode 3 (square wave **
- ** mode), and it completes a "cycle" in 0.054926 seconds (~1/18.207 **
- ** seconds). The reason I say "normally" is because it is possible to **
- ** change the length of the cycle, which changes the timer's frequency. **
- ** This is NOT what the following code does. **
- ** **
- ** System timer 0 has its own 16 bit counter. Here is some simplified **
- ** pseudo-code of what system timer 0 does with its counter when it is **
- ** operating in mode 3, and its frequency has not been tampered with: **
- ** **
- ** counter = 65536 **
- ** while (counter != 0) **
- ** counter -= 2; **
- ** counter = 65536 **
- ** while (counter != 0) **
- ** counter -= 2; **
- ** **
- ** You read that right. The counter is decremented from 65536 to 0 **
- ** TWICE. This is somewhat unfortunate, because we want to read that **
- ** counter to use for our timing operations because it is very accurate. **
- ** The counter is decremented 65536 times in one timer cycle (32768 **
- ** times in each while loop above). So, the time between decrements is: **
- ** **
- ** (0.054926 seconds/cycle) / (65536 decrements/cycle) = **
- ** 0.000000838 seconds/decrement = 838ns/decrement **
- ** **
- ** Since the counter is decremented to 0 twice in each timer cycle, we **
- ** would only be able to time events that take no longer than 0.027463 **
- ** seconds (one half of the timer cycle, the duration of one of the **
- ** while loops above). **
- ** **
- ** The solution used by the code in this file is to change the timer's **
- ** operation mode to mode 2. Here is some simplified pseudo-code of what **
- ** system timer 0 does with its counter when it is operating in mode 2, **
- ** and its frequency has not been tampered with: **
- ** **
- ** counter = 65536 **
- ** while (counter != 0) **
- ** counter -= 1; **
- ** **
- ** This solves any problems concerning the ambiguity of determining **
- ** which while loop is executing when we read the counter from the timer. **
- ** But now, we have a 16 bit value which can only be used to time events **
- ** which take no longer than 0.054926 seconds (duration of one cycle). **
- ** **
- ** The solution used by this code is to make use of another timer: **
- ** the "large timer", which is a 32-bit value at memory location **
- ** 0x40:0x6C. Conveniently, this "large timer" is incremented each time **
- ** system timer 0 completes a cycle (once each 0.054926 seconds). **
- ** The code in this file generates 32-bit values to represent the **
- ** time. Obviously, we can't pack in the 16 bit counter and the 32 bit **
- ** large timer into the 32 bit time type, so we cut off the high order **
- ** 16 bits of the large timer. The following picture describes how the **
- ** time value is generated using the timers: **
- ** **
- ** 31 0 15 0 **
- ** ------------------------------------------- ---------------------- **
- ** | L a r g e T i m e r | | 65535 - Counter | **
- ** ------------------------------------------- ---------------------- **
- ** | | | **
- ** \|/ \|/ \|/ **
- ** V V V **
- ** 31 16 15 0 **
- ** ---------------------- ---------------------- **
- ** | t T I M E | **
- ** ---------------------- ---------------------- **
- ** **
- ** (Note that we have to use (65535-Counter) because Counter is being **
- ** decremented by the timer, but time is increasing) **
- ** **
- **=========================================================================**
- ** USING THIS MODULE **
- ** Before calling any other timing routine, you must call TM_Init(n), **
- ** where n specifies the number of timers your application needs. **
- ** It may be a good idea to call TM_Init() in the initialization **
- ** portion of your application. **
- ** **
- ** To begin timing an event, make a call to TM_StartTimer(tid), **
- ** where tid is an integer in the range [0..(n-1)] which specifies **
- ** which of the n timers you are starting. **
- ** **
- ** To compute the duration of the event, just call **
- ** TM_ElapsedTime(tid), where tid is the same integer used in the **
- ** call to TM_StartTimer(). **
- ** **
- ** When you are finished with the timing routines, call TM_Close(). **
- ** This should fit in nicely with the cleanup section of your **
- ** application. **
- ** **
- ** If your application NEEDS to handle the time computations itself, **
- ** the function TM_ReadTimer(tid) is also available. This function **
- ** will return the current time (MOD 1 hour, approximately). I **
- ** discourage use of this function, but discovered that I need it **
- ** for another module/library... **
- ** **
- ** EXAMPLES **
- ** A simple delaying routine: **
- ** void delay( tTIME duration ) **
- ** { **
- ** TM_StartTimer(0); **
- ** while (TM_ElapsedTime(0) < duration) **
- ** ; **
- ** } **
- ** **
- ** A fixed frame-rate game: **
- ** TM_Init(1); **
- ** while (player_not_dead) **
- ** { **
- ** TM_StartTimer(0); **
- ** MoveMonsters(); **
- ** MovePlayers(); **
- ** UpdateDisplay(); **
- ** while (TM_ElapsedTime(0) < frame_duration) **
- ** ; **
- ** } **
- ** TM_Close(); **
- \***************************************************************************/
-
- #include <dos.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "timer.h"
-
- /*-------------------------------- MACROS ---------------------------------*/
-
- /* macro to return the current value of the large timer */
-
- #define TM_LARGE_TIMER (*((unsigned long far *)MK_FP(0x40, 0x6C)))
-
- /*--------------------------- GLOBAL VARIABLES ----------------------------*/
-
- /* starting times for all of the timers this code will support */
-
- tTIME *gpTM_start_time = NULL;
-
- unsigned int gTM_max_timers = 0;
-
- /* flag to let us know if it is ok to run the timing routines */
- /* (1 = NOT safe, 0 = safe) */
-
- unsigned char gTM_module_not_initialized = 1;
-
- /*------------------------- Error Message Strings -------------------------*/
-
- #define TM_ERR_STR_GENERAL \
- "General (unspecified) error."
- #define TM_ERR_STR_UNINITIALIZED \
- "Timing routines not yet initialized.\n" \
- "(TM_Init() has not been called)"
- #define TM_ERR_STR_BAD_TIMER_ID \
- "Application specified an invalid timer ID."
- #define TM_ERR_STR_ALLOC \
- "Unable to allocate dynamic memory."
- #define TM_ERR_STR_ZERO_TIMERS \
- "Application requested 0 timers.\n" \
- "(must request 1 or more timers to use this module)"
-
- /*------------------------- Error Message Indices -------------------------*/
- /* (Make sure these indices are accurate according to gpTM_error_text[] */
- /* declared below !!) */
-
- #define TM_ERR_GENERAL 0
- #define TM_ERR_UNINITIALIZED 1
- #define TM_ERR_BAD_TIMER_ID 2
- #define TM_ERR_ALLOC 3
- #define TM_ERR_ZERO_TIMERS 4
-
- /*------------------------- Error Message Strings -------------------------*/
- /* (Make sure the positions of the error messages in this array are */
- /* accurately represented by the error messages indices listed above !!) */
-
- char *gpTM_error_text[] =
- {
- TM_ERR_STR_GENERAL,
- TM_ERR_STR_UNINITIALIZED,
- TM_ERR_STR_BAD_TIMER_ID,
- TM_ERR_STR_ALLOC,
- TM_ERR_STR_ZERO_TIMERS
- };
-
- /***************************************************************************\
- ** void _TM_Error( ) **
- *****************************************************************************
- ** ARGUMENTS **
- ** const char *pCalling_function_name **
- ** (I) name of the calling function **
- ** int error_number **
- ** (I) integer identifier of the error that occurred **
- ** const char *pCustom_message **
- ** (I) additional message text to be displayed **
- **-------------------------------------------------------------------------**
- ** RETURNS **
- ** void **
- **-------------------------------------------------------------------------**
- ** EXAMPLE USAGE (NOT INTENDED FOR EXTERNAL USE) **
- ** if ( gTM_module_not_initialized ) **
- ** { **
- ** _TM_Error ( pFunction_name, TM_ERR_UNINITIALIZED, NULL ); <-<< **
- ** return; **
- ** } **
- **-------------------------------------------------------------------------**
- ** DETECTABLE ERROR CONDITIONS **
- ** None **
- **-------------------------------------------------------------------------**
- ** DESCRIPTION **
- ** This function will generate a message which will be sent to stderr **
- ** to inform the user of an error. This message will include the **
- ** name of the function the error occurred in (if supplied), a canned **
- ** error string for the error indicated, and a custom string (if **
- ** supplied) which may provide more details about th error. **
- **-------------------------------------------------------------------------**
- ** LIMITATIONS **
- ** The message text must not exceed 1024 bytes in size, which can **
- ** store over 12 80-character lines of text. **
- \***************************************************************************/
-
- void _TM_Error ( pCalling_function_name, error_number, pCustom_message )
- const char *pCalling_function_name;
- int error_number;
- const char *pCustom_message;
- {
- char error_message[1024]; /* buffer for message text */
-
- /*---------------------------------------------------------------------*\
- ** Insert the "ERROR IN MODULE "TIMER"" header string into our **
- ** message. **
- \*---------------------------------------------------------------------*/
-
- sprintf ( error_message,
- "\n******** ERROR IN MODULE \"TIMER\" *********\n" );
-
- /*---------------------------------------------------------------------*\
- ** Insert the name of the function in which the error was discovered. **
- ** This should always be provided, but check for NULL to be safe. **
- \*---------------------------------------------------------------------*/
-
- strcat ( error_message, "FUNCTION: " );
-
- if ( pCalling_function_name != (char *)NULL )
- strcat ( error_message, pCalling_function_name );
- else
- strcat ( error_message, "<not specified - kill the programmer>" );
-
- strcat ( error_message, "\n" );
-
- /*---------------------------------------------------------------------*\
- ** Insert the canned error message text for the specified error **
- ** number. **
- \*---------------------------------------------------------------------*/
-
- strcat ( error_message, gpTM_error_text[error_number] );
- strcat ( error_message, "\n" );
-
- /*---------------------------------------------------------------------*\
- ** Insert the custom_message, if it is supplied. This custom message **
- ** should provide more detailed information than the generic error **
- ** strings. **
- \*---------------------------------------------------------------------*/
-
- if ( pCustom_message != (char *)NULL )
- {
- strcat ( error_message, pCustom_message );
- } /* end if ( custom message was supplied ) */
-
- strcat ( error_message, "\n" );
-
- /*---------------------------------------------------------------------*\
- ** Send the message off to stderr. **
- \*---------------------------------------------------------------------*/
-
- fprintf ( stderr, "%s", error_message );
-
- } /* end _TM_Error ( ) */
-
- /***************************************************************************\
- ** tTIME TM_ReadTime( ) **
- *****************************************************************************
- ** ARGUMENTS **
- ** void **
- **-------------------------------------------------------------------------**
- ** RETURNS **
- ** tTIME - the current time measured in units of 838ns **
- **-------------------------------------------------------------------------**
- ** EXAMPLE USAGE (NOT INTENDED FOR EXTERNAL USE) **
- ** InitializeApplication(); **
- ** TM_Init(1); **
- ** . . . **
- ** current_time = TM_ReadTime( ); <-----<< **
- ** . . . **
- ** TM_Close(); **
- ** ShutDownApplication(); **
- **-------------------------------------------------------------------------**
- ** DETECTABLE ERROR CONDITIONS **
- ** * Module has not been initialized (TM_Init() not called) **
- **-------------------------------------------------------------------------**
- ** DESCRIPTION **
- ** This function generates a 32-bit value in units of 838ns. This **
- ** value spans a time period of about one hour. The high 16 bits of **
- ** this value come from the large timer (the 32-bit value at **
- ** 0x40:0x6C, the number of timer cycles since midnight), and the **
- ** low 16 bits come from system timer 0's counter. **
- ** **
- ** NOTE: System timer 0's counter repeatedly cycles from 65535 down **
- ** to 0 (decremented), but time is steadily increasing. To **
- ** get a steadily increasing value from this timer, we subtract **
- ** the actual value of the counter from 65535. **
- **-------------------------------------------------------------------------**
- ** LIMITATIONS **
- ** The value returned by this function is the current time MOD **
- ** (approximately) one hour, not the time of day. It is only useful **
- ** useful for timing events that finish within an hour. **
- \***************************************************************************/
-
- tTIME TM_ReadTime ( void )
- {
- register unsigned char LSB; /* least significant byte */
- register unsigned char MSB; /* most significant byte */
- char *pFunction_name = /* This function's name, used for */
- "TM_ReadTime()"; /* error reporting */
-
- /*---------------------------------------------------------------------*\
- ** Handle uninitialized module error. **
- \*---------------------------------------------------------------------*/
-
- if ( gTM_module_not_initialized )
- {
- _TM_Error ( pFunction_name, TM_ERR_UNINITIALIZED, NULL );
- return( (tTIME) (-1) );
- } /* end if */
-
- /*---------------------------------------------------------------------*\
- ** By writing 0x00 to port 0x43, we are specifying the following **
- ** command: **
- ** bits 76 = 00 --> timer 0 **
- ** bits 54 = 00 --> reading 16-bit value: lsb followed by msb **
- ** bits 321 = 000 --> ignored **
- ** bit 0 = 0 --> ignored **
- \*---------------------------------------------------------------------*/
-
- outportb ( 0x43, 0x00 );
-
- /*---------------------------------------------------------------------*\
- ** The following two statements reading from port 0x40 are reading **
- ** system timer 0's 16-bit counter: MSB after LSB. **
- \*---------------------------------------------------------------------*/
-
- LSB = inportb ( 0x40 ); /* get low order byte */
- MSB = inportb ( 0x40 ); /* get high order byte */
-
- /*---------------------------------------------------------------------*\
- ** Pack the time into the 32-bit tTIME return value. **
- ** (see the preamble at the top of this file for more details) **
- \*---------------------------------------------------------------------*/
-
- return( (unsigned long int) (TM_LARGE_TIMER << 16)
- | (unsigned int) (0xFFFF-((((unsigned int)MSB)<<8)|LSB)));
-
- } /* end TM_ReadTime() */
-
- /***************************************************************************\
- ** void TM_StartTimer( tid ) **
- *****************************************************************************
- ** ARGUMENTS **
- ** unsigned int tid **
- ** (I) integer label, which is used as an index into the array **
- ** of timers (gpTM_start_time[]) **
- **-------------------------------------------------------------------------**
- ** RETURNS **
- ** void **
- **-------------------------------------------------------------------------**
- ** EXAMPLE USAGE **
- ** #define THIRTYITH_OF_A_SECOND 39759 **
- ** #define DELAY_TIMER 0 **
- ** InitializeApplication(); **
- ** TM_Init(1); **
- ** . . . **
- ** TM_StartTimer(DELAY_TIMER); <-----<< **
- ** MoveMonsters(); **
- ** MovePlayers(); **
- ** UpdateDisplay(); **
- ** while (TM_ElapsedTime(DELAY_TIMER) < THIRTYITH_OF_A_SECOND) **
- ** ; **
- ** . . . **
- ** TM_Close(); **
- ** ShutDownApplication(); **
- **-------------------------------------------------------------------------**
- ** DETECTABLE ERROR CONDITIONS **
- ** * Module has not been initialized (TM_Init() not called) **
- ** * tid is out of range (range = [0..(gTM_max_timers-1)]) **
- **-------------------------------------------------------------------------**
- ** DESCRIPTION **
- ** This procedure starts a pseudo-timer by reading the current time **
- ** and storing it in the global array gpTM_start_time[]. **
- **-------------------------------------------------------------------------**
- ** LIMITATIONS **
- ** None **
- \***************************************************************************/
-
- void TM_StartTimer ( tid )
- unsigned int tid;
- {
- char custom_message[256]; /* Buffer for custom error message */
- char *pFunction_name = /* This function's name, used for */
- "TM_StartTimer()"; /* error reporting */
-
- /*---------------------------------------------------------------------*\
- ** Handle uninitialized module error. **
- \*---------------------------------------------------------------------*/
-
- if (gTM_module_not_initialized)
- {
- _TM_Error ( pFunction_name, TM_ERR_UNINITIALIZED, NULL );
- return;
- } /* end if */
-
- if ( tid < gTM_max_timers ) /* then tid is valid */
- {
- /*-----------------------------------------------------------------*\
- ** The timer ID is valid, so mark the starting time for this **
- ** timer (tid) **
- \*-----------------------------------------------------------------*/
-
- gpTM_start_time[tid] = TM_ReadTime ( );
- }
- else /* tid is out of range */
- {
- /*-----------------------------------------------------------------*\
- ** Handle the bad timer ID error. **
- \*-----------------------------------------------------------------*/
-
- sprintf ( custom_message, "Request received for timer %u, but the "
- "last valid timer is timer %u.\n",
- tid, gTM_max_timers-1 );
- _TM_Error ( pFunction_name, TM_ERR_BAD_TIMER_ID, custom_message );
- } /* end if */
- } /* end TM_StartTimer() */
-
- /***************************************************************************\
- ** tTIME TM_ElapsedTime( tid ) **
- *****************************************************************************
- ** ARGUMENTS **
- ** unsigned int tid **
- ** (I) integer label, which is used as an index into the array of **
- ** timers (gpTM_start_time[]) **
- **-------------------------------------------------------------------------**
- ** RETURNS **
- ** tTIME - the amount of time that has passed since the last call **
- ** to TM_StartTimer(tid), measured in units of 838ns **
- **-------------------------------------------------------------------------**
- ** EXAMPLE USAGE: **
- ** #define THIRTYITH_OF_A_SECOND 39759 **
- ** #define DELAY_TIMER 0 **
- ** InitializeApplication(); **
- ** TM_Init(1); **
- ** . . . **
- ** TM_StartTimer(DELAY_TIMER); **
- ** MoveMonsters(); **
- ** MovePlayers(); **
- ** UpdateDisplay(); **
- ** while (TM_ElapsedTime(DELAY_TIMER) < THIRTYITH_OF_A_SECOND) <---<< **
- ** ; **
- ** . . . **
- ** TM_Close(); **
- ** ShutDownApplication(); **
- **-------------------------------------------------------------------------**
- ** DETECTABLE ERROR CONDITIONS **
- ** * Module has not been initialized (TM_Init() not called) **
- ** * tid is out of range (range = [0..(gTM_max_timers-1)]) **
- **-------------------------------------------------------------------------**
- ** DESCRIPTION **
- ** This function calculates the time that has elapsed for timer slot **
- ** tid since the last call to TM_StartTimer(tid) by getting the **
- ** current time and subtracting the starting time (stored in global **
- ** array gpTM_start_time[].) **
- **-------------------------------------------------------------------------**
- ** LIMITATIONS **
- ** The largest elapsed time that can accurately be measured is **
- ** approximately one hour: **
- ** (tTIME = unsigned long int = 32-bits) **
- ** (65536(ticks/cycle)*18.2(cycles/sec)*3600 ~= 2^32) **
- \***************************************************************************/
-
- tTIME TM_ElapsedTime ( tid )
- unsigned int tid;
- {
- char custom_message[256]; /* Buffer for custom error message */
- char *pFunction_name = /* This function's name, used for */
- "TM_ElapsedTime()"; /* error reporting */
-
- /*---------------------------------------------------------------------*\
- ** Handle uninitialized module error. **
- \*---------------------------------------------------------------------*/
-
- if ( gTM_module_not_initialized )
- {
- _TM_Error( pFunction_name, TM_ERR_UNINITIALIZED, NULL );
- return( (tTIME) (-1) );
- } /* end if */
-
- if ( tid < gTM_max_timers ) /* then tid is valid */
- {
- /*-----------------------------------------------------------------*\
- ** The timer ID is valid, so compute the elapsed time. **
- \*-----------------------------------------------------------------*/
-
- return( TM_ReadTime ( ) - gpTM_start_time[tid] );
- }
- else /* tid is out of range */
- {
- /*-----------------------------------------------------------------*\
- ** Handle the bad timer ID error. **
- \*-----------------------------------------------------------------*/
-
- sprintf ( custom_message, "Request received for timer %u, but the "
- "last valid timer is timer %u.\n",
- tid, gTM_max_timers-1 );
- _TM_Error ( pFunction_name, TM_ERR_BAD_TIMER_ID, custom_message );
- return( (tTIME) (-1) );
- } /* end if */
- } /* end TM_ElapsedTime() */
-
- /***************************************************************************\
- ** int TM_Init( ) **
- *****************************************************************************
- ** ARGUMENTS **
- ** unsigned int num_timers **
- ** (I) number of timers the application is requesting **
- **-------------------------------------------------------------------------**
- ** RETURNS **
- ** int - non-zero means an error occurred **
- ** 0 if the timer module was successfully initialized **
- **-------------------------------------------------------------------------**
- ** EXAMPLE USAGE **
- ** InitializeApplication(); **
- ** TM_Init(1); <-----<< **
- ** . . . **
- ** ApplicationBody(); **
- ** . . . **
- ** TM_Close(); **
- ** ShutDownApplication(); **
- **-------------------------------------------------------------------------**
- ** DETECTABLE ERROR CONDITIONS **
- ** * Invalid number of timers requested (0) **
- ** * Failed to allocated memory for array of pseudo-timers **
- **-------------------------------------------------------------------------**
- ** DESCRIPTION **
- ** This procedure sets timer 0 to operation mode 2, and allocates **
- ** memory to store starting times for the specified number of **
- ** (pseudo)timers. **
- ** **
- ** The gTM_module_not_initialized is set to 0 to express that the **
- ** module has been initialized, so the code can be used correctly. **
- **-------------------------------------------------------------------------**
- ** LIMITATIONS **
- ** None **
- \***************************************************************************/
-
- int TM_Init ( num_timers )
- unsigned int num_timers;
- {
- char custom_message[256]; /* Buffer for custom error message */
- char *pFunction_name = /* This function's name, used for */
- "TM_Init()"; /* error reporting */
-
- /*---------------------------------------------------------------------*\
- ** Make sure this code doesn't get executed more than once before **
- ** TM_Close(). We would allocate a new array of timers, and lose **
- ** the previously allocated array (memory leak). **
- \*---------------------------------------------------------------------*/
-
- if ( !gTM_module_not_initialized )
- {
- return ( 0 ); /* return success */
- /* (this isn't an error, just stupid) */
- }
-
- /*---------------------------------------------------------------------*\
- ** Allocate an array of qseudo-timers **
- \*---------------------------------------------------------------------*/
-
- if ( num_timers > 0 )
- {
- gpTM_start_time = (tTIME *) calloc ( num_timers, sizeof ( tTIME ) );
-
- if ( gpTM_start_time == NULL )
- {
- sprintf ( custom_message,
- "Failed to allocate %u timers of size %u.\n",
- num_timers, (unsigned int) sizeof ( tTIME ) );
- _TM_Error ( pFunction_name, TM_ERR_ALLOC, custom_message );
- return ( -1 );
- } /* end if */
-
- gTM_max_timers = num_timers;
- }
- else /* num_timers == 0, since num_timers is an unsigned int */
- {
- /*-----------------------------------------------------------------*\
- ** Application requested 0 timers, which is pointless. **
- \*-----------------------------------------------------------------*/
-
- _TM_Error ( pFunction_name, TM_ERR_ZERO_TIMERS, NULL );
- return ( -1 );
- } /* end if-else */
-
- /*---------------------------------------------------------------------*\
- ** Set timer to operation mode 2 **
- ** **
- ** By writing 0x34 to port 0x43, we are specifying: **
- ** (0x34 = 00110100) **
- ** bits 76 = 00 --> timer 0 **
- ** bits 54 = 11 --> writing 16-bit value: lsb followed by msb **
- ** bits 321 = 010 --> operation mode 2 **
- ** bit 0 = 0 --> binary counter operation **
- \*---------------------------------------------------------------------*/
-
- outportb ( 0x43, 0x34 );
-
- /*---------------------------------------------------------------------*\
- ** The following two statements writing 0x00 to port 0x40 are writing **
- ** a 16-bit value of 0x0000 to the timer's counter, which specifies **
- ** that the counter is to begin its cycle with a value of 65536 **
- ** (0x10000), which specifies a maximum length cycle (54.926ms). **
- \*---------------------------------------------------------------------*/
-
- outportb ( 0x40, 0x00 );
- outportb ( 0x40, 0x00 );
-
- /*---------------------------------------------------------------------*\
- ** Unlock this module **
- \*---------------------------------------------------------------------*/
-
- gTM_module_not_initialized = 0;
-
- return ( 0 ); /* initialization successful */
-
- } /* TM_Init() */
-
- /***************************************************************************\
- ** void TM_Close( ) **
- *****************************************************************************
- ** ARGUMENTS **
- ** void **
- **-------------------------------------------------------------------------**
- ** RETURNS **
- ** void **
- **-------------------------------------------------------------------------**
- ** EXAMPLE USAGE **
- ** InitializeApplication(); **
- ** TM_Init(1); **
- ** . . . **
- ** ApplicationBody(); **
- ** . . . **
- ** TM_Close(); <-----<< **
- ** ShutDownApplication(); **
- **-------------------------------------------------------------------------**
- ** DETECTABLE ERROR CONDITIONS **
- ** * Module has not been initialized (TM_Init() not called) **
- **-------------------------------------------------------------------------**
- ** DESCRIPTION **
- ** This procedure returns system timer 0 to operation mode 3, and **
- ** deallocates the memory used to store the starting times for each **
- ** of the (pseudo)timers. **
- ** **
- ** The gTM_module_not_initialized is set to 1 to prevent further use **
- ** of this module. This module will remain locked until TM_Init() **
- ** is called. **
- **-------------------------------------------------------------------------**
- ** LIMITATIONS **
- ** None **
- \***************************************************************************/
-
- void TM_Close ( void )
- {
- char *pFunction_name = /* This function's name, used for */
- "TM_Close()"; /* error reporting */
-
- /*---------------------------------------------------------------------*\
- ** Handle uninitialized module error. **
- \*---------------------------------------------------------------------*/
-
- if ( gTM_module_not_initialized )
- {
- _TM_Error ( pFunction_name, TM_ERR_UNINITIALIZED, NULL );
- return;
- } /* end if */
-
- /*---------------------------------------------------------------------*\
- ** Deallocate the array of pseudo-timers **
- \*---------------------------------------------------------------------*/
-
- if ( gpTM_start_time != NULL )
- {
- free ( gpTM_start_time );
- gpTM_start_time = NULL;
- } /* end if */
-
- /*---------------------------------------------------------------------*\
- ** Set timer to operation mode 3 **
- ** **
- ** By writing 0x36 to port 0x43, we are specifying: **
- ** (0x36 = 00110110) **
- ** bits 76 = 00 --> timer 0 **
- ** bits 54 = 11 --> writing 16-bit value: lsb followed by msb **
- ** bits 321 = 011 --> operation mode 3 **
- ** bit 0 = 0 --> binary counter operation **
- \*---------------------------------------------------------------------*/
-
- outportb ( 0x43, 0x36 );
-
- /*---------------------------------------------------------------------*\
- ** The following two statements writing 0x00 to port 0x40 are writing **
- ** a 16-bit value of 0x0000 to the timer's counter, which specifies **
- ** that the counter is to begin its cycle with a value of 65536 **
- ** (0x10000), which specifies a maximum length cycle (54.926ms). **
- \*---------------------------------------------------------------------*/
-
- outportb ( 0x40, 0x00 );
- outportb ( 0x40, 0x00 );
-
- /*---------------------------------------------------------------------*\
- ** Lock this module **
- \*---------------------------------------------------------------------*/
-
- gTM_module_not_initialized = 1;
-
- } /* end TM_Close ( ) */
-